#include <iostream>
#include <unistd.h>     // 系统调用相关功能，本代码中用于sleep(10)
#include <thread>
#include <functional>
#include <mutex>

using std::cout;
using std::endl;
using std::thread;
using std::function;

// 子线程与主线程执行速度问题
void threadFunc0()
{
    cout << "void threadFunc0()" << endl;
}

void test0()
{
    // 进入主线程
    cout << "int test0" << endl;
    // 创建线程对象th
    thread th(threadFunc0);

    // 方案3：主线程等待子线程
    th.join();

    cout << "test0 finished..." << endl;
    // 方案1：sleep
    // sleep(10);
    // 方案2：while
    // while(1);
    cout << "======" << endl << endl;
}

// 1: 普通函数调用
void threadFunc1(int x)
{
    cout << "void threadFunc1(int)" << endl;
    cout << "x = " << x << endl;
    cout << "child1 thread id = " << std::this_thread::get_id() << endl;
}

void test1()
{
    // 进入主线程
    cout << "int test1 id = " << std::this_thread::get_id() << endl;
    // 创建线程对象th
    thread th(threadFunc1, 1);

    cout << "child thread id = " << th.get_id() << endl;

    // 主线程等待子线程
    th.join();

    cout << "test1 finished..." << endl;
    cout << "======" << endl << endl;
}


// 2: 函数指针调用
void threadFunc2(int x)
{
    cout << "void threadFunc2(int)" << endl;
    cout << "x = " << x << endl;
    cout << "child thread id = " << std::this_thread::get_id() << endl;
}

void test2()
{
    // 进入主线程
    cout << "int test2 id = " << std::this_thread::get_id() << endl;
    
    // 定义函数指针
    typedef void (*pFunc)(int);
    // 函数指针f指向threadFunc2
    pFunc f = &threadFunc2;

    // 创建线程对象th
    thread th(threadFunc2, 2);

    cout << "child thread id = " << th.get_id() << endl;

    // 主线程等待子线程
    th.join();

    cout << "test2 finished..." << endl;
    cout << "======" << endl << endl;
}

// 3: 函数引用调用
void threadFunc3(int x)
{
    cout << "void threadFunc3(int)" << endl;
    cout << "x = " << x << endl;
    cout << "child thread id = " << std::this_thread::get_id() << endl;
}

void test3()
{
    // 进入主线程
    cout << "int test3 id = " << std::this_thread::get_id() << endl;
    
    // 定义函数指针
    typedef void (&pFunc)(int);
    // 函数指针f指向threadFunc2
    pFunc f = threadFunc3;

    // 创建线程对象th
    thread th(threadFunc3, 3);

    cout << "child thread id = " << th.get_id() << endl;

    // 主线程等待子线程
    th.join();

    cout << "test3 finished..." << endl;
    cout << "======" << endl << endl;
}

// 4: 成员函数调用
class Example4
{
public:
    void threadFunc4(int x)
    {
        cout << "void threadFunc4(int)" << endl;
        cout << "x = " << x << endl;
        cout << "child thread id = " << std::this_thread::get_id() << endl;
    }
};

void test4()
{
    // 进入主线程
    cout << "int test4 id = " << std::this_thread::get_id() << endl;
    
    // 创建Example4类的实例（栈上对象）
    Example4 ex;
    // 构建线程，调用成员函数：绑定成员函数地址，对象地址(传参隐含this指针)，参数值
    thread th(&Example4::threadFunc4, &ex, 4);
    // 将对象地址改为对象也可以
    // thread th(&Example4::threadFunc4, ex, 4); 

    cout << "child thread id = " << th.get_id() << endl;

    // 主线程等待子线程
    th.join();

    cout << "test4 finished..." << endl;
    cout << "======" << endl << endl;
}

// 5: 函数对象调用
class Example5
{
public:
    // 这个重载让对象变成“函数”
    void operator()(int x)
    {
        cout << "void operator()" << endl;
        cout << "x = " << x << endl;
        cout << "child thread id = " << std::this_thread::get_id() << endl;
    }
};

void test5()
{
    // 进入主线程
    cout << "int test5 id = " << std::this_thread::get_id() << endl;
    
    // 创建Example4类的实例（栈上对象）
    Example5 ex;
    // 调用函数对象（重载operator）
    // 1: thread th(ex, 5); 需要传一个函数与参数，其中函数是ex，参数是5；
    // 2：ex之所以能被传送，是因为被当作函数对象；
    // 3：ex之所以被当成了函数对象，是因为重载了();
    // 4：编译器伪代码，将ex转化为ex->operator()(5); 
    // -- C++规定，如果传给thread的第一个参数是对象而非函数指针，就尝试自动调用它的operator()
    // -- 只有()能被当作函数调用，其余[] {} 都不能当作函数对象调用
    // 5: 简单理解，此处相当于调用函数名
    thread th(ex, 5);

    cout << "child thread id = " << th.get_id() << endl;

    // 主线程等待子线程
    th.join();

    cout << "test5 finished..." << endl;
    cout << "======" << endl << endl;
}

// 6: lambda函数调用
void test6()
{
    // 进入主线程
    cout << "int test6 id = " << std::this_thread::get_id() << endl;
    
    thread th([](int x){
              cout << "void threadFunc(int)" << endl;
              cout << "x = " << x << endl;
              cout << "child2 thread id = " << std::this_thread::get_id() << endl;
              }, 6);

    cout << "child thread id = " << th.get_id() << endl;

    // 主线程等待子线程
    th.join();

    cout << "test6 finished..." << endl;
    cout << "======" << endl << endl;
}

// 7: Function函数调用
std::mutex cout_mutex;
void threadFunc7(int x)
{
    std::lock_guard<std::mutex> lock(cout_mutex);
    cout << "void threadFunc7(int)" << endl;
    cout << "x = " << x << endl;
    cout << "child thread id = " << std::this_thread::get_id() << endl;
 }

void test7()
{
    // 进入主线程
    cout << "int test7 id = " << std::this_thread::get_id() << endl;

    // 直接将 threadFunc7 函数包装成 std::function 对象 f1，保留了参数列表 (int)
    function<void(int)> f1 = threadFunc7;
    // 使用 std::bind 绑定 threadFunc7，并通过占位符 _1 表示第一个参数由调用时传入i, _1是坑, 如果此处将_1改为固定参数，7会被忽略
    function<void(int)> f2 = bind(threadFunc7, std::placeholders::_1);

    thread th1(f1, 7);
    thread th2(f2, 7);  // 7 填入 _1 的位置

    cout << "child thread id = " << th1.get_id() << endl;

    // 主线程等待子线程
    th1.join();
    th2.join();

    cout << "test7 finished..." << endl;
    cout << "======" << endl << endl;
}


// 8: Bind调用
void threadFunc8(int x)
{
    cout << "void threadFunc8(int)" << endl;
    cout << "x = " << x << endl;
    cout << "child thread id = " << std::this_thread::get_id() << endl;
 }

void test8()
{
    // 进入主线程
    cout << "int test8 id = " << std::this_thread::get_id() << endl;

    thread th(std::bind(threadFunc8, 8));

    cout << "child thread id = " << th.get_id() << endl;

    // 主线程等待子线程
    th.join();

    cout << "test4 finished..." << endl;
    cout << "======" << endl << endl;
}

int main()
{
    test0();
    test1();
    test2();
    test3();
    test4();
    test5();
    test6();
    test7();
    test8();

    return 0;
}

